[ElementTiming] Add element ID The element ID helps developers and analytics providers determine which element the PerformanceElementTiming entry is referring to. While we have other ways to find out the element for Image Element Timing (for\ example, we can use the image requested URL), for text the available resources will be much limited and thus ID is needed. Bug: 879270, 942033 Change-Id: I0f20609cf4edc7eb6431448c439b9cf911f89fb9 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1544948 Commit-Queue: Nicolás Peña Moreno <npm@chromium.org> Reviewed-by: Chris Harrelson <chrishtr@chromium.org> Cr-Commit-Position: refs/heads/master@{#646432} 
diff --git a/element-timing/buffer-before-onload.html b/element-timing/buffer-before-onload.html index d3772c0..805777f 100644 --- a/element-timing/buffer-before-onload.html +++ b/element-timing/buffer-before-onload.html 
@@ -18,6 +18,7 @@  const img = document.createElement('img');  img.src = 'resources/square20.jpg';  img.setAttribute('elementtiming', 'my_image'); + img.setAttribute('id', 'my_id');  document.body.appendChild(img);  window.onload = t.step_func_done( () => {  const entries = performance.getEntriesByType('element'); @@ -27,7 +28,7 @@  const index = window.location.href.lastIndexOf('/');  const pathname = window.location.href.substring(0, index) +  '/resources/square20.jpg'; - checkElement(entry, pathname, 'my_image', beforeRender); + checkElement(entry, pathname, 'my_image', 'my_id', beforeRender);  checkNaturalSize(entry, 20, 20);  });  }, "Element Timing: image loads before onload."); 
diff --git a/element-timing/cross-origin-element.sub.html b/element-timing/cross-origin-element.sub.html index c0912f3..b1a5b7c 100644 --- a/element-timing/cross-origin-element.sub.html +++ b/element-timing/cross-origin-element.sub.html 
@@ -18,7 +18,7 @@  t.step_func_done((entryList) => {  assert_equals(entryList.getEntries().length, 1);  const entry = entryList.getEntries()[0]; - checkElement(entry, pathname, 'my_image', 0); + checkElement(entry, pathname, 'my_image', 'the_id', 0);  assert_equals(entry.startTime, 0,  'The startTime of a cross-origin image should be 0.');  checkRect(entry, [0, 100, 0, 100]); @@ -34,6 +34,7 @@  const img = document.createElement('img');  img.src = pathname;  img.setAttribute('elementtiming', 'my_image'); + img.setAttribute('id', 'the_id');  document.body.appendChild(img);  });  }, 'Cross-origin image element is NOT observable.'); 
diff --git a/element-timing/image-TAO-wildcard.sub.html b/element-timing/image-TAO-wildcard.sub.html index 4c40717..0e24af0 100644 --- a/element-timing/image-TAO-wildcard.sub.html +++ b/element-timing/image-TAO-wildcard.sub.html 
@@ -19,7 +19,7 @@  t.step_func_done((entryList) => {  assert_equals(entryList.getEntries().length, 1);  const entry = entryList.getEntries()[0]; - checkElement(entry, img_src, 'my_image', beforeRender); + checkElement(entry, img_src, 'my_image', 'my_id', beforeRender);  // Assume viewport has size at least 20, so the element is fully visible.  checkRect(entry, [0, 20, 0, 20]);  checkNaturalSize(entry, 20, 20); @@ -33,6 +33,7 @@  const img = document.createElement('img');  img.src = img_src;  img.setAttribute('elementtiming', 'my_image'); + img.setAttribute('id', 'my_id');  img.onload = t.step_func(() => {  // After a short delay, assume that the entry was not dispatched.  t.step_timeout(() => { 
diff --git a/element-timing/image-carousel.html b/element-timing/image-carousel.html index f914f74..9f0ef79 100644 --- a/element-timing/image-carousel.html +++ b/element-timing/image-carousel.html 
@@ -17,10 +17,10 @@    <div class="slideshow-container">  <div class='carousel-image'> - <img src="resources/circle.svg" elementtiming='image0'> + <img src="resources/circle.svg" elementtiming='image0' id='image0'>  </div>  <div class='carousel-image'> - <img src="resources/square100.png" elementtiming='image1'> + <img src="resources/square100.png" elementtiming='image1' id='image1'>  </div>  </div>   @@ -37,13 +37,13 @@  const observer = new PerformanceObserver(list => {  list.getEntries().forEach(entry => {  if (entry_count % 2 == 0) { - checkElement(entry, pathname0, 'image0', beforeRenderTimes[entry_count]); + checkElement(entry, pathname0, 'image0', 'image0', beforeRenderTimes[entry_count]);  checkRect(entry, [0, 200, 0, 200]);  checkNaturalSize(entry, 200, 200);  entry_count_per_element[0]++;  }  else { - checkElement(entry, pathname1, 'image1', beforeRenderTimes[entry_count]); + checkElement(entry, pathname1, 'image1', 'image1', beforeRenderTimes[entry_count]);  checkRect(entry, [0, 100, 0, 100]);  checkNaturalSize(entry, 100, 100);  entry_count_per_element[1]++; 
diff --git a/element-timing/image-clipped-svg.html b/element-timing/image-clipped-svg.html index 54c074c..36cf1b1 100644 --- a/element-timing/image-clipped-svg.html +++ b/element-timing/image-clipped-svg.html 
@@ -14,7 +14,7 @@  const index = window.location.href.lastIndexOf('/');  const pathname = window.location.href.substring(0, index) +  '/resources/circle.svg'; - checkElement(entry, pathname, 'my_svg', beforeRender); + checkElement(entry, pathname, 'my_svg', 'SVG', beforeRender);  // Image size is 200x200 but SVG size is 100x100 so it is clipped.  checkRect(entry, [0, 100, 0, 100]);  checkNaturalSize(entry, 200, 200); @@ -30,5 +30,5 @@  }  </style>  <svg width="100" height="100"> - <image href='resources/circle.svg' elementtiming='my_svg'/> + <image href='resources/circle.svg' elementtiming='my_svg' id='SVG'/>  </svg> 
diff --git a/element-timing/image-not-fully-visible.html b/element-timing/image-not-fully-visible.html index b61a948..279fa03 100644 --- a/element-timing/image-not-fully-visible.html +++ b/element-timing/image-not-fully-visible.html 
@@ -20,7 +20,7 @@  const index = window.location.href.lastIndexOf('/');  const pathname = window.location.href.substring(0, index) +  '/resources/square20.png'; - checkElement(entry, pathname, 'not_fully_visible', beforeRender); + checkElement(entry, pathname, 'not_fully_visible', '', beforeRender);  // Image will not be fully visible. It should start from the top left part  // of the document, excluding the margin, and then overflow.  checkRect(entry, 
diff --git a/element-timing/image-rect-iframe.html b/element-timing/image-rect-iframe.html index f94b259..94c872e 100644 --- a/element-timing/image-rect-iframe.html +++ b/element-timing/image-rect-iframe.html 
@@ -22,6 +22,7 @@  assert_equals(rect.bottom, 100);  assert_equals(e.data.naturalWidth, 100);  assert_equals(e.data.naturalHeight, 100); + assert_equals(e.data.id, 'iframe_img_id');  t.done();  });  }, 'Element Timing entry in iframe has coordinates relative to the iframe.'); 
diff --git a/element-timing/image-with-css-scale.html b/element-timing/image-with-css-scale.html index 4cd0830..6d77429 100644 --- a/element-timing/image-with-css-scale.html +++ b/element-timing/image-with-css-scale.html 
@@ -28,7 +28,7 @@  const index = window.location.href.lastIndexOf('/');  const pathname = window.location.href.substring(0, index - 14) +  'images/black-rectangle.png'; - checkElement(entry, pathname, 'rectangle', beforeRender); + checkElement(entry, pathname, 'rectangle', 'rect_id', beforeRender);  checkRect(entry, [0, 200, 25, 125]);  checkNaturalSize(entry, 100, 50);  }) @@ -36,7 +36,7 @@  observer.observe({entryTypes: ['element']});  }, 'Image intersectionRect is affected by scaling, but not its intrinsic size.');  </script> -<div class="my_div"> - <img src="/images/black-rectangle.png" elementtiming="rectangle"/> +<div class="my_div" id='div_id'> + <img src="/images/black-rectangle.png" elementtiming="rectangle" id='rect_id'/>  </div>  </body> 
diff --git a/element-timing/image-with-rotation.html b/element-timing/image-with-rotation.html index 4e00c68..70b635e 100644 --- a/element-timing/image-with-rotation.html +++ b/element-timing/image-with-rotation.html 
@@ -28,7 +28,7 @@  const index = window.location.href.lastIndexOf('/');  const pathname = window.location.href.substring(0, index - 14) +  'images/black-rectangle.png'; - checkElement(entry, pathname, 'rectangle', beforeRender); + checkElement(entry, pathname, 'rectangle', 'rect_id', beforeRender);  checkNaturalSize(entry, 100, 50);  const rect = entry.intersectionRect;  // The div rotates with respect to the origin, so part of it will be invisible. @@ -44,7 +44,7 @@  observer.observe({entryTypes: ['element']});  }, 'Image intersectionRect is affected by rotation, but not its intrinsic size.');  </script> -<div class="my_div"> - <img src="/images/black-rectangle.png" elementtiming="rectangle"/> +<div class="my_div" id="div_id"> + <img src="/images/black-rectangle.png" elementtiming="rectangle" id="rect_id"/>  </div>  </body> 
diff --git a/element-timing/images-repeated-resource.html b/element-timing/images-repeated-resource.html index 7ad00e0..dbcad24 100644 --- a/element-timing/images-repeated-resource.html +++ b/element-timing/images-repeated-resource.html 
@@ -22,7 +22,7 @@  const observer = new PerformanceObserver(  t.step_func(function(entryList) {  entryList.getEntries().forEach(entry => { - checkElement(entry, pathname, entry.identifier, beforeRender); + checkElement(entry, pathname, entry.identifier, 'image_id', beforeRender);  checkNaturalSize(entry, 100, 100);  if (entry.identifier === 'my_image') {  ++numEntries; @@ -47,11 +47,13 @@  const img = document.createElement('img');  img.src = 'resources/square100.png';  img.setAttribute('elementtiming', 'my_image'); + img.setAttribute('id', 'image_id');  document.body.appendChild(img);    const img2 = document.createElement('img');  img2.src = 'resources/square100.png';  img2.setAttribute('elementtiming', 'my_image2'); + img2.setAttribute('id', 'image_id');  document.body.appendChild(img2);    beforeRender = performance.now(); 
diff --git a/element-timing/observe-elementtiming.html b/element-timing/observe-elementtiming.html index c9755a8..39fea05 100644 --- a/element-timing/observe-elementtiming.html +++ b/element-timing/observe-elementtiming.html 
@@ -20,7 +20,7 @@  const index = window.location.href.lastIndexOf('/');  const pathname = window.location.href.substring(0, index) +  '/resources/square100.png'; - checkElement(entry, pathname, 'my_image', beforeRender); + checkElement(entry, pathname, 'my_image', 'my_id', beforeRender);  // Assume viewport has size at least 100, so the element is fully visible.  checkRect(entry, [0, 100, 0, 100]);  checkNaturalSize(entry, 100, 100); @@ -34,6 +34,7 @@  const img = document.createElement('img');  img.src = 'resources/square100.png';  img.setAttribute('elementtiming', 'my_image'); + img.setAttribute('id', 'my_id');  document.body.appendChild(img);  beforeRender = performance.now();  }; 
diff --git a/element-timing/observe-large-image.html b/element-timing/observe-large-image.html index 3a3149b..a08274c 100644 --- a/element-timing/observe-large-image.html +++ b/element-timing/observe-large-image.html 
@@ -20,7 +20,7 @@  const index = window.location.href.lastIndexOf('/');  const pathname = window.location.href.substring(0, index) +  '/resources/square20.jpg'; - checkElement(entry, pathname, '', beforeRender); + checkElement(entry, pathname, '', 'large_one', beforeRender);  // Assume viewport hasn't changed, so the element occupies all of it.  checkRect(entry,  [0, document.documentElement.clientWidth, 0, document.documentElement.clientHeight]); @@ -36,6 +36,7 @@  img.src = 'resources/square20.jpg';  img.width = document.documentElement.clientWidth;  img.height = document.documentElement.clientHeight; + img.setAttribute('id', 'large_one');  document.body.appendChild(img);  beforeRender = performance.now();  }; 
diff --git a/element-timing/observe-multiple-images.html b/element-timing/observe-multiple-images.html index 79f991f..05c54ac 100644 --- a/element-timing/observe-multiple-images.html +++ b/element-timing/observe-multiple-images.html 
@@ -34,7 +34,8 @@  image1Observed = 1;  const pathname1 = window.location.href.substring(0, index) +  '/resources/square100.png'; - checkElement(entry, pathname1, 'image1', beforeRender); + // The images do not contain ID, so expect an empty ID. + checkElement(entry, pathname1, 'image1', 'img1', beforeRender);  // This image is horizontally centered.  // Using abs and comparing to 1 because the viewport sizes could be odd.  // If a size is odd, then image cannot be in the pure center, but left @@ -58,7 +59,7 @@  image2Observed = 1;  const pathname2 = window.location.href.substring(0, index) +  '/resources/square20.png'; - checkElement(entry, pathname2, 'image2', beforeRender); + checkElement(entry, pathname2, 'image2', 'img2', beforeRender);  // This image should be below image 1, and should respect the margin.  checkRect(entry, [50, 250, 250, 450], "of image2");  checkNaturalSize(entry, 20, 20); @@ -71,7 +72,7 @@  image3Observed = 1;  const pathname3 = window.location.href.substring(0, index) +  '/resources/circle.svg'; - checkElement(entry, pathname3, 'image3', beforeRender); + checkElement(entry, pathname3, 'image3', 'img3', beforeRender);  // This image is just to the right of image2.  checkRect(entry, [250, 450, 250, 450], "of image3");  checkNaturalSize(entry, 200, 200); @@ -90,6 +91,7 @@  function addImage(number, source, width=0) {  const img = document.createElement('img');  img.src = source; + // Set a different id and elementtiming value for each image.  img.id = 'img' + number;  img.setAttribute('elementtiming', 'image' + number);  if (width !== 0) 
diff --git a/element-timing/observe-svg-image.html b/element-timing/observe-svg-image.html index ea45374..45e800d 100644 --- a/element-timing/observe-svg-image.html +++ b/element-timing/observe-svg-image.html 
@@ -14,7 +14,7 @@  const index = window.location.href.lastIndexOf('/');  const pathname = window.location.href.substring(0, index) +  '/resources/circle.svg'; - checkElement(entry, pathname, 'my_svg', beforeRender); + checkElement(entry, pathname, 'my_svg', 'svg_id', beforeRender);  // Assume viewport has size at least 200, so the element is fully visible.  checkRect(entry, [0, 200, 0, 200]);  checkNaturalSize(entry, 200, 200); @@ -30,5 +30,5 @@  }  </style>  <svg width="300" height="300"> - <image href='resources/circle.svg' elementtiming='my_svg'/> + <image href='resources/circle.svg' elementtiming='my_svg' id='svg_id'/>  </svg> 
diff --git a/element-timing/observe-video-poster.html b/element-timing/observe-video-poster.html index 41e6edf..d3a6993 100644 --- a/element-timing/observe-video-poster.html +++ b/element-timing/observe-video-poster.html 
@@ -14,7 +14,7 @@  const index = window.location.href.lastIndexOf('/');  const pathname = window.location.href.substring(0, index) +  '/resources/circle.svg'; - checkElement(entry, pathname, 'my_poster', beforeRender); + checkElement(entry, pathname, 'my_poster', 'the_poster', beforeRender);  // Assume viewport has size at least 200, so the element is fully visible.  checkRect(entry, [0, 200, 0, 200]);  checkNaturalSize(entry, 200, 200); @@ -29,4 +29,4 @@  margin: 0;  }  </style> -<video elementtiming='my_poster' src='/media/test.mp4' poster='resources/circle.svg'/> +<video elementtiming='my_poster' id='the_poster' src='/media/test.mp4' poster='resources/circle.svg'/> 
diff --git a/element-timing/progressively-loaded-image.html b/element-timing/progressively-loaded-image.html index 63ba9a3..c0a7d4f 100644 --- a/element-timing/progressively-loaded-image.html +++ b/element-timing/progressively-loaded-image.html 
@@ -24,7 +24,7 @@  img_src;  // Since the image is only fully loaded after the sleep, the render timestamp  // must be greater than |beforeRender| + |sleep|. - checkElement(entry, pathname, 'my_image', beforeRender + sleep); + checkElement(entry, pathname, 'my_image', '', beforeRender + sleep);  checkNaturalSize(entry, 20, 20);  })  ); 
diff --git a/element-timing/rectangular-image.html b/element-timing/rectangular-image.html index 9903d47..b028084 100644 --- a/element-timing/rectangular-image.html +++ b/element-timing/rectangular-image.html 
@@ -21,7 +21,7 @@  // Subtracting 14 to remove 'element-timing'.  const pathname = window.location.href.substring(0, index - 14) +  'images/black-rectangle.png'; - checkElement(entry, pathname, 'my_image', beforeRender); + checkElement(entry, pathname, 'my_image', 'rectangle', beforeRender);  // Assume viewport has size at least 100, so the element is fully visible.  checkRect(entry, [20, 120, 20, 70]);  checkNaturalSize(entry, 100, 50); @@ -34,6 +34,7 @@  // Add image of width equal to 100 and height equal to 50.  const img = document.createElement('img');  img.src = '/images/black-rectangle.png'; + img.id = 'rectangle';  img.setAttribute('elementtiming', 'my_image');  document.body.appendChild(img);  beforeRender = performance.now(); 
diff --git a/element-timing/resources/element-timing-helpers.js b/element-timing/resources/element-timing-helpers.js index 2462c2d..66605df 100644 --- a/element-timing/resources/element-timing-helpers.js +++ b/element-timing/resources/element-timing-helpers.js 
@@ -1,10 +1,11 @@  // Checks that this is an ElementTiming entry with name |expectedName|. It also  // does a very basic check on |startTime|: after |beforeRender| and before now(). -function checkElement(entry, expectedName, expectedIdentifier, beforeRender) { +function checkElement(entry, expectedName, expectedIdentifier, expectedID, beforeRender) {  assert_equals(entry.entryType, 'element');  assert_equals(entry.name, expectedName);  assert_equals(entry.identifier, expectedIdentifier);  assert_equals(entry.duration, 0); + assert_equals(entry.id, expectedID);  assert_greater_than_equal(entry.startTime, beforeRender);  assert_greater_than_equal(performance.now(), entry.startTime);  const rt_entries = performance.getEntriesByName(expectedName, 'resource'); 
diff --git a/element-timing/resources/iframe-with-square-sends-entry.html b/element-timing/resources/iframe-with-square-sends-entry.html index 1165a78..25bd679 100644 --- a/element-timing/resources/iframe-with-square-sends-entry.html +++ b/element-timing/resources/iframe-with-square-sends-entry.html 
@@ -14,10 +14,11 @@  'rect' : entryList.getEntries()[0].intersectionRect,  'naturalWidth' : entryList.getEntries()[0].naturalWidth,  'naturalHeight' : entryList.getEntries()[0].naturalHeight, + 'id': entryList.getEntries()[0].id,  }, '*');  });  observer.observe({entryTypes: ['element']});  </script> -<img src=square100.png elementtiming=my_image/> +<img src=square100.png id=iframe_img_id elementtiming=my_image/>  </body>  </html>